import React, { useContext, useEffect, useState } from "react";
import { Form, Table, Popconfirm, Button } from "antd";
import { DeleteOutlined, PlusOutlined } from "@ant-design/icons";
import PropTypes from "prop-types";

const EditableContext = React.createContext(null);
const EditableRow = ({ ...props }) => {
  const [form] = Form.useForm();

  if (props.pushFormList) {
    props.pushFormList(form);
    delete props.pushFormList;
  }

  const onBlur = (e) => {
    // 判断是否是行失去焦点
    if (e.relatedTarget && e.currentTarget.contains(e.relatedTarget)) {
      return;
    }
    props.onBlur && props.onBlur(form);
  };

  return (
    <Form form={form} component={false}>
      <EditableContext.Provider value={form}>
        <tr {...props} onBlur={onBlur} />
      </EditableContext.Provider>
    </Form>
  );
};
EditableRow.propTypes = {
  pushFormList: PropTypes.func,
  onBlur: PropTypes.func,
};

/**
 *
 * @param {Object} record 行数据
 * @param {String} dataIndex 列字段
 * @param {Array} rules 单元格组件校验规则，对Checkbox组件无效
 * @param {Function} handleSave 保存回调函数 function handleSave(record, index)
 * @returns
 */
const EditableCell = ({ dataIndex, record, rules = [], children, ...restProps }) => {
  const form = useContext(EditableContext);

  useEffect(() => {
    const [, value] = children;
    if (value && typeof value !== "object" && !form.getFieldValue(dataIndex)) {
      form.setFieldValue(dataIndex, value);
    }
  }, [children, dataIndex, form]);

  return (
    <td {...restProps}>
      <Form.Item name={dataIndex} rules={rules}>
        {children}
      </Form.Item>
    </td>
  );
};
EditableCell.propTypes = {
  dataIndex: PropTypes.string,
  record: PropTypes.object,
  rules: PropTypes.array,
  children: PropTypes.node,
};

const EditorTableComponent = ({
  dataSource: datas = [],
  columns,
  formList,
  options = true,
  rowBlurValidate = true,
  onChange,
  onRowDelete,
  ...resProp
}) => {
  const [dataSource, setDataSource] = useState(datas);
  const [indexKey, setIndexKey] = useState(() => dataSource.length);

  // 添加行
  const onInset = () => {
    const index = indexKey + 1;
    const data = dataSource.concat({ key: index });
    setIndexKey(index);
    setDataSource(data);
  };

  // 删除行
  const handleDelete = (v, _, index) => {
    const newData = dataSource.filter((item) => item.key !== v.key);
    setDataSource(newData);
    onRowDelete && onRowDelete(v);
    onChange && onChange(newData, v, index);
  };

  // 保存数据
  const handleSave = (v, index) => {
    const newData = [...dataSource];
    newData[index] = v;
    setDataSource(newData);
    onChange && onChange(newData, v, index);
  };

  const onConfirm = (e, _, record, index) => {
    e.stopPropagation();
    handleDelete(_, record, index);
  };

  // 操作列
  const optionsColums = {
    title: (
      <Button type="link" style={{ padding: "0px 12px" }} size="small" icon={<PlusOutlined />} onClick={onInset}>
        添加行
      </Button>
    ),
    width: "120px",
    align: "center",
    render: (_, record, index) => (
      <Popconfirm
        title="是否确定删除该行?"
        onCancel={(e) => e.stopPropagation()}
        onConfirm={(e) => onConfirm(e, _, record, index)}
      >
        <Button type="link" danger icon={<DeleteOutlined />} onBlur={(e) => e.stopPropagation()}>
          删除
        </Button>
      </Popconfirm>
    ),
  };

  const newColumns = columns.map((col) => {
    const onCell = (record) => {
      const { dataIndex, rules } = col;
      return { record, dataIndex, rules };
    };

    return { ...col, onCell };
  });

  const onBlur = (form, [record, index]) => {
    const res = form.getFieldsValue();
    handleSave({ ...record, ...res }, index);
    rowBlurValidate && form.validateFields();
  };

  return (
    <Table
      className="editor-table"
      {...resProp}
      components={{ body: { row: EditableRow, cell: EditableCell } }}
      dataSource={dataSource}
      columns={newColumns.concat(options === true ? optionsColums : [])}
      pagination={{ hideOnSinglePage: true, defaultPageSize: "50" }}
      onRow={(...record) => {
        return {
          onBlur: (form) => onBlur(form, record),
          pushFormList: (form) => formList && formList.add(form),
        };
      }}
    />
  );
};
EditorTableComponent.propTypes = {
  dataSource: PropTypes.array,
  columns: PropTypes.array,
  formList: PropTypes.object,
  options: PropTypes.bool,
  rowBlurValidate: PropTypes.bool,
  onChange: PropTypes.func,
  onRowDelete: PropTypes.func,
};

export default EditorTableComponent;
